package com.yyfax.pay.third.facade.fuiou;

import static com.yyfax.framework.yyfax.enums.RspCodeEnum.COMMON_ERROR_UNKNOWN_EXCEPTION;
import static com.yyfax.pay.common.enums.PayRspCodeEnum.PAY_CODE_QUERY_ORDER_FAIL;

import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.yyfax.pay.third.model.to.fuiou.*;
import com.yyfax.pay.third.model.to.fuiou.xml.*;
import com.yyfax.pay.third.model.to.yyfax.*;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.NotImplementedException;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.math.NumberUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.alibaba.fastjson.JSON;
import com.fuiou.mpay.encrypt.DESCoderFUIOU;
import com.fuiou.util.MD5;
import com.google.common.collect.Maps;
import com.yyfax.commons.json.JacksonUtil;
import com.yyfax.commons.lang.DateUtil;
import com.yyfax.framework.common.Log;
import com.yyfax.framework.model.Content;
import com.yyfax.framework.model.Params;
import com.yyfax.framework.yyfax.enums.YesNoEnum;
import com.yyfax.pay.common.constants.FuiouRespConstant;
import com.yyfax.pay.common.constants.PayConstants;
import com.yyfax.pay.common.enums.FuiouCardTypeEnum;
import com.yyfax.pay.common.enums.FuiouPayoutStateEnum;
import com.yyfax.pay.common.enums.PayModeEnum;
import com.yyfax.pay.common.enums.PayRspCodeEnum;
import com.yyfax.pay.common.enums.PayTypeEnum;
import com.yyfax.pay.common.enums.PaymentEnum;
import com.yyfax.pay.common.exception.PayExceptionCode;
import com.yyfax.pay.common.exception.YYPayException;
import com.yyfax.pay.common.util.CommonIdUtils;
import com.yyfax.pay.common.util.FuiouSignUtil;
import com.yyfax.pay.config.data.service.BankConfigExtService;
import com.yyfax.pay.config.data.service.BankConfigService;
import com.yyfax.pay.config.data.service.MerchantPaymentService;
import com.yyfax.pay.config.model.po.BankConfigExtPO;
import com.yyfax.pay.config.model.po.BankConfigPO;
import com.yyfax.pay.config.model.po.MerchantPaymentPO;
import com.yyfax.pay.order.model.vo.PayBusiIdVO;
import com.yyfax.pay.order.service.PayCommonService;
import com.yyfax.pay.third.service.PayInfoConstantService;
import com.yyfax.pay.third.service.TransformService;

/**
 * 富友支付实体转换
 *
 * @author heizq
 * @date 2017-04-21 10:52:53
 * @since v1.0.0
 */
@Service("fuiouTransformService")
public class FuiouTransformService implements TransformService {

	@Autowired
	private MerchantPaymentService merchantPaymentService;

	@Autowired
	private PayInfoConstantService fuiouPayInfoService;

	@Autowired
	private BankConfigExtService bankConfigExtService;

	@Autowired
	private PayCommonService payCommonService;

	@Autowired
	private PayConstants payConstants;

	@Autowired
	private BankConfigService bankConfigService;

	private static Logger logger = LoggerFactory.getLogger(FuiouApi.class);

	@SuppressWarnings({ "unchecked" })
	@Override
	public <P extends Params> P transformQueryPayOrderParams(QueryPayOrderYYParams req) throws Exception {
		try {
			logger.debug("【pay】【FUIOU】查单请求参数:{}", JacksonUtil.nonullMapper.toJson(req));

			FuiouExtConstant fuiouConstan = fuiouPayInfoService.getMerchantInfo(FuiouExtConstant.class, req.getMerchantCode(), PaymentEnum.FUIOU,
					PayTypeEnum.PAY, PayModeEnum.AUTH_PAY);

			String version = fuiouConstan.getQueryVersion();
			String merchantId = fuiouConstan.getMerchantId();
			String merchantSecurit = fuiouConstan.getMerchantSecurit();
			String mchtOrderId = req.getPayOrderId();

			String sign = MD5.MD5Encode(new StringBuffer().append(version).append("|").append(merchantId).append("|").append(mchtOrderId).append("|")
					.append(merchantSecurit).toString());

			QueryPayOrderData queryPayOrderData = new QueryPayOrderData();
			queryPayOrderData.setVersion(version);
			queryPayOrderData.setMchntcd(merchantId);
			queryPayOrderData.setMchntorderid(mchtOrderId);
			queryPayOrderData.setSign(sign);

			String fm = queryPayOrderData.toXml();
			logger.info("【pay】【FUIOU】订单号：{}，请求xml:{}", mchtOrderId, fm);

			Map<String, String> params = new HashMap<String, String>();
			params.put("FM", fm);

			QueryOrderByOrderNumFuiouParams queryOrderByOrderNumFuiouParams = new QueryOrderByOrderNumFuiouParams();
			queryOrderByOrderNumFuiouParams.setUrl(fuiouConstan.getQueryUrl());
			queryOrderByOrderNumFuiouParams.setParams(params);
			queryOrderByOrderNumFuiouParams.setOrderId(mchtOrderId);

			return (P) queryOrderByOrderNumFuiouParams;
		} catch (Exception e) {
			logger.error("【pay】【FUIOU】查单请求封装出错！orderId:" + req.getPayOrderId(), e);
			throw new YYPayException(PayRspCodeEnum.COMMON_ERROR_UNKNOWN_EXCEPTION, "查单请求参数封装失败！");
		}
	}

	@Override
	public <C extends Content> QueryPayOrderYYContent transformQueryPayOrderContent(C rsp) throws Exception {
		QueryOrderByOrderNumFuiouContent content = (QueryOrderByOrderNumFuiouContent) rsp;
		try {
			QueryPayOrderYYContent queryPayOrderYYContent = new QueryPayOrderYYContent();
			if (content == null) {
				queryPayOrderYYContent.setResultCode(PayRspCodeEnum.PAY_CODE_PAY_FAIL.getValue());
				return queryPayOrderYYContent;
			}
			logger.debug("【pay】【FUIOU】查单响应参数:{}", content.toString());

			// 支付id解析
			PayBusiIdVO payOrderIdVo = CommonIdUtils.getPayBusiIdVo(content.getMchntOrderId());
			FuiouExtConstant fuiouConstan = fuiouPayInfoService.getMerchantInfo(FuiouExtConstant.class, payOrderIdVo.getMerchantCode(),
					PaymentEnum.FUIOU, PayTypeEnum.PAY, PayModeEnum.AUTH_PAY);

			// 校验签名
			if (validateSign(content, fuiouConstan)) {
				switch (content.getResponseCode()) {
				// 处理中
				case FuiouRespConstant.RESPONSECODE_HANGUP_1:
				case FuiouRespConstant.RESPONSECODE_HANGUP_2:
				case FuiouRespConstant.RESPONSECODE_HANGUP_3: {
					queryPayOrderYYContent.setResultCode(PayRspCodeEnum.PAY_CODE_DEALING.getValue());
					queryPayOrderYYContent.setResultMsg("处理中");
					logger.info("【pay】【FUIOU】富友支付交易挂起状态订单，订单号：{}，resultMsg:{}", content.getMchntOrderId(), content.getResponseMsg());
					break;
				}
				// 成功
				case FuiouRespConstant.RESPONSECODE_SUCCESS:
				case FuiouRespConstant.RESPONSECODE_QUERY_SUCCESS: {
					queryPayOrderYYContent.setResultCode(PayRspCodeEnum.SUCCESS.getValue());
					queryPayOrderYYContent.setResultMsg(content.getResponseMsg());
					logger.info("【pay】【FUIOU】富友支付交易成功状态订单，订单号：{}", content.getMchntOrderId());
					break;
				}
				default: {
					// 订单不存在或失败的状态
					queryPayOrderYYContent.setResultCode(PayRspCodeEnum.PAY_CODE_PAY_FAIL.getValue());
					queryPayOrderYYContent.setResultMsg(content.getResponseMsg());
					logger.info("【pay】【FUIOU】富友支付交易查询失败，订单号为:{},的订单交易状态异常:{}", content.getMchntOrderId(), content.getResponseMsg());
				}
				}
				queryPayOrderYYContent.setOrderId(content.getMchntOrderId());
			} else {
				queryPayOrderYYContent.setResultCode(PayRspCodeEnum.PAY_CODE_CHECK_SIGN_FAIL.getValue());
				queryPayOrderYYContent.setResultMsg("查询订单验签失败");
				logger.error("【pay】【FUIOU】查询订单验签失败！orderId:{}", content.getMchntOrderId());
			}

			queryPayOrderYYContent.setSerialNo(queryPayOrderYYContent.getOrderId());
			queryPayOrderYYContent.setRspContent(content.getRspContent());
			return queryPayOrderYYContent;
		} catch (Exception e) {
			logger.error("【pay】【FUIOU】查单响应处理出错！orderId:" + content, e);
			throw new YYPayException(PayRspCodeEnum.COMMON_ERROR_UNKNOWN_EXCEPTION, "查单响应处理失败！");
		}
	}

	@Override
	public <P extends Params> P transformAuthenticationParams(AuthenticationYYParams req) {
		throw new NotImplementedException("富友支付不支持");
	}

	@Override
	public <C extends Content> AuthenticationYYContent transformAuthenticationContent(C rsp) {
		throw new NotImplementedException("富友支付不支持");
	}

	@Override
	public <P extends Params> P transformBatchPayoutOrderCheckParams(QueryBatchPayoutOrderCheckYYParams req) {
		throw new NotImplementedException("富友支付不支持");
	}

	@Override
	public <C extends Content> QueryBatchPayoutOrderCheckYYContent transformBatchPayoutOrderCheckContent(C rsp) {
		throw new NotImplementedException("富友支付不支持");
	}

	@Override
	public <P extends Params> P transformBatchPayoutOrderParams(PayoutBatchOrderYYParams req) {
		throw new NotImplementedException("富友支付不支持");
	}

	@Override
	public <C extends Content> PayoutBatchOrderYYContent transformBatchPayoutOrderContent(C rsp) {
		throw new NotImplementedException("富友支付不支持");
	}

	@SuppressWarnings("unchecked")
	@Override
	public <P extends Params> P transformPayOrdeParams(PayOrderYYParams req) throws Exception {
		try {
			logger.debug("【pay】【FUIOU】支付请求参数:{}", req.toString());

			FuiouExtConstant fuiouConstan = fuiouPayInfoService.getMerchantInfo(FuiouExtConstant.class, req.getMerchantCode(), PaymentEnum.FUIOU,
					PayTypeEnum.PAY, PayModeEnum.AUTH_PAY);

			PayReqData payReqData = new PayReqData();
			payReqData.setVersion(fuiouConstan.getVersion());
			payReqData.setUserip(req.getUserIp());
			payReqData.setType(fuiouConstan.getType());
			payReqData.setMchntorderid(req.getPayOrderId());
			payReqData.setUserid(req.getUserId());
			payReqData.setOrderid(req.getSerialNo());
			payReqData.setBankcard(req.getCardNo());
			payReqData.setMobile(req.getPhone());
			payReqData.setVercd(req.getValidCode());
			payReqData.setSigntp(fuiouConstan.getSignType());
			payReqData.setMchntcd(fuiouConstan.getMerchantId());

			String signPlain = new StringBuffer().append(payReqData.getType()).append("|").append(payReqData.getVersion()).append("|")
					.append(fuiouConstan.getMerchantId()).append("|").append(payReqData.getOrderid()).append("|").append(payReqData.getMchntorderid())
					.append("|").append(payReqData.getUserid()).append("|").append(payReqData.getBankcard()).append("|").append(payReqData.getVercd())
					.append("|").append(payReqData.getMobile()).append("|").append(payReqData.getUserip()).append("|")
					.append(fuiouConstan.getMerchantSecurit()).toString();
			logger.debug("【pay】【FUIOU】富友支付，支付sign:{}", signPlain);

			String sign = MD5.MD5Encode(signPlain);
			payReqData.setSign(sign);
			payReqData.setSignpay(req.getToken());
			payReqData.setVercd(req.getValidCode());
			logger.info("【pay】【FUIOU】富友支付，支付xml:{}", JSON.toJSONString(payReqData));

			// 请求参数加密
			Map<String, String> param = new HashMap<String, String>();
			param.put("MCHNTCD", fuiouConstan.getMerchantId());
			param.put("APIFMS", DESCoderFUIOU.desEncrypt(payReqData.toXml(), DESCoderFUIOU.getKeyLength8(fuiouConstan.getMerchantSecurit())));

			// 日志请求参数明文
			Map<String, String> logParams = new HashMap<String, String>();
			logParams.put("MCHNTCD", fuiouConstan.getMerchantId());
			logParams.put("APIFMS", payReqData.toXml());

			PayOrderFuiouParams payOrderFuiouParams = new PayOrderFuiouParams();
			payOrderFuiouParams.setParams(param);
			payOrderFuiouParams.setMerchantSecurit(fuiouConstan.getMerchantSecurit());
			payOrderFuiouParams.setUrl(fuiouConstan.getPayUrl());
			payOrderFuiouParams.setUserId(req.getUserId());
			payOrderFuiouParams.setLogParams(logParams);

			return (P) payOrderFuiouParams;
		} catch (Exception e) {
			logger.error("【pay】【FUIOU】支付请求参数封装出错！orderId:" + req.getPayOrderId(), e);
			throw new YYPayException(PayRspCodeEnum.COMMON_ERROR_UNKNOWN_EXCEPTION, "支付请求参数封装失败！");
		}
	}

	@Override
	public <C extends Content> PayOrderYYContent transformPayOrdeContent(C rsp) throws Exception {
		PayOrderFuiouContent payOrderFuiouContent = (PayOrderFuiouContent) rsp;
		try {
			PayOrderYYContent payOrderYYContent = new PayOrderYYContent();
			if (payOrderFuiouContent == null) {
				payOrderYYContent.setResultCode(PayRspCodeEnum.PAY_CODE_PAY_FAIL.getValue());
				return payOrderYYContent;
			}
			logger.info("【pay】【FUIOU】订单号：{}，富友支付响应参数！result:{}", payOrderFuiouContent.getOrderid(), payOrderFuiouContent.toString());
			// 支付id解析
			PayBusiIdVO payOrderIdVo = CommonIdUtils.getPayBusiIdVo(payOrderFuiouContent.getMchntorderid());
			FuiouExtConstant fuiouConstan = fuiouPayInfoService.getMerchantInfo(FuiouExtConstant.class, payOrderIdVo.getMerchantCode(),
					PaymentEnum.FUIOU, PayTypeEnum.PAY, PayModeEnum.AUTH_PAY);

			// 验签
			if (validateSign(payOrderFuiouContent, fuiouConstan)) {
				// 成功
				if (FuiouRespConstant.RESPONSECODE_SUCCESS.equals(payOrderFuiouContent.getResponsecode())
						|| FuiouRespConstant.RESPONSECODE_QUERY_SUCCESS.equals(payOrderFuiouContent.getResponsecode())) {
					logger.info("【pay】【FUIOU】订单号：{}，支付成功！", payOrderFuiouContent.getMchntorderid());
					payOrderYYContent.setResultCode(PayRspCodeEnum.SUCCESS.getValue());
					// 响应文案，修改成“支付成功”
					// payOrderYYContent.setResultMsg(payOrderFuiouContent.getResponsemsg());
					payOrderYYContent.setResultMsg("支付成功");
					payOrderYYContent.setSerialNo(payOrderFuiouContent.getOrderid());
				}
				// 验证码无效或错误
				else if (FuiouRespConstant.VALIDATE_CODE_ERROR.equals(payOrderFuiouContent.getResponsecode())) {
					logger.info("【pay】【FUIOU】订单号：{}，支付验证码错误或无效！result:{}", payOrderFuiouContent.getOrderid(), payOrderFuiouContent.toString());
					payOrderYYContent.setResultCode(PayRspCodeEnum.PAY_CODE_WARN_ILLEGAL_VALID_CODE.getValue());
					payOrderYYContent.setResultMsg("验证码错误或失效");
				}
				// 处理中
				else if (FuiouRespConstant.RESPONSECODE_UNGETBANKRESULT.equals(payOrderFuiouContent.getResponsecode())) {
					logger.info("【pay】【FUIOU】订单号：{}，支付订单挂起！result:{}", payOrderFuiouContent.getOrderid(), payOrderFuiouContent.toString());
					payOrderYYContent.setResultCode(PayRspCodeEnum.PAY_CODE_DEALING.getValue());
					payOrderYYContent.setResultMsg("支付处理中，请稍后");
				}
				// 失败
				else {
					logger.info("【pay】【FUIOU】订单号：{}，支付失败！result:{}", payOrderFuiouContent.getOrderid(), payOrderFuiouContent.toString());
					payOrderYYContent.setResultCode(PayRspCodeEnum.PAY_CODE_PAY_FAIL.getValue());
					payOrderYYContent.setResultMsg(payOrderFuiouContent.getResponsemsg());
				}
				payOrderYYContent.setAmount(Integer.valueOf(payOrderFuiouContent.getAmt()));
				payOrderYYContent.setPayOrderId(payOrderFuiouContent.getMchntorderid());
			} else {
				payOrderYYContent.setResultCode(PayRspCodeEnum.PAY_CODE_CHECK_SIGN_FAIL.getValue());
				payOrderYYContent.setResultMsg("支付验签失败");
				logger.error("【pay】【FUIOU】富友支付查询订单验签失败！orderId:{}", payOrderFuiouContent.getMchntorderid());
			}

			payOrderYYContent.setRspContent(payOrderFuiouContent.getRsqContent());
			return payOrderYYContent;
		} catch (Exception e) {
			logger.error("【pay】【FUIOU】支付响应处理出错！orderId:" + payOrderFuiouContent, e);
			throw new YYPayException(PayRspCodeEnum.COMMON_ERROR_UNKNOWN_EXCEPTION, "支付响应处理失败！");
		}
	}

	@SuppressWarnings("unchecked")
	@Override
	public <P extends Params> P transformPayoutOrderParams(PayoutOrderYYParams rsp) throws Exception {
		// 获取富友商户代付信息
		MerchantPaymentPO merchant = merchantPaymentService.queryByThirdMerchantCode(rsp.getMerchantCode(), PaymentEnum.FUIOU.getValue(),
				PayTypeEnum.PAY_OUT.getValue(), PayModeEnum.AUTH_PAY.getValue());
		logger.info("【lianlian】【pay】查询支付通过信息成功,merchant:{}", JacksonUtil.nonullMapper.toJson(merchant));
		if (merchant == null) {
			logger.error("【lianlian】【pay】查询支付通过信息失败,商户信息为空,merchantCode:{}", rsp.getMerchantCode());
			throw new YYPayException(PayRspCodeEnum.PAY_CODE_PAY_FAIL.getValue(), "查询支付通过信息失败,商户信息为空.");
		}
		return (P) buildPayOutOrderFuiouParams(merchant, rsp);
	}

	/**
	 * 根据商户信息和代付订单，构建代付请求对象
	 *
	 * @param MerchantPaymentPO
	 * @param PayoutOrderYYParams
	 * @return
	 * @throws Exception
	 */
	private PayoutOrderFuiouParams buildPayOutOrderFuiouParams(MerchantPaymentPO merchant, PayoutOrderYYParams rsp) throws Exception {
		final String op = "FuiouTransformService.buildPayOutOrderFuiouParams";
		// 富友只能用纯数字的流水号
		// 代付新版本之后，payoutOrderId会根据通道生成流水号，不需要再截取，edit by buyi since 2.1.5
		// String fuiouOrderNo = rsp.getPayoutOrderId().substring(2);
		String fuiouOrderNo = rsp.getPayoutOrderId();
		if (!NumberUtils.isDigits(fuiouOrderNo)) {
			// throw new YYPayException(PayRspCodeEnum.COMMON_ERROR_PARAMETER_INVALID, "富友订单号必须为纯数字,订单号是:" + rsp.getPayoutOrderId());
			logger.warn(Log.op(op).msg("富友 | 代付 | 代付业务参数校验异常，富友代付订单号必须为纯数字").kv("PayoutOrderId", rsp.getPayoutOrderId()).toString());
			throw PayExceptionCode.ERROR_ILL_PARAMETER.exp();
		}

		FuiouPayOutExtConstant ext = getPayOutExt(merchant);
		PayOutReqData payOut = new PayOutReqData();
		payOut.setVer(ext.getVersion());
		payOut.setCityNo(ext.getCityNo());

//		payOut.setMerDate(DateUtil.date2Str(new Date(), "yyyyMMdd"));
		payOut.setMerDate(DateUtil.date2Str(DateUtil.str2DateTime(rsp.getPayOrderTime()), "yyyyMMdd"));
		payOut.setOrderNo(fuiouOrderNo);

		// 获取总行号
		QueryCardBinContent cardBin = payCommonService.queryCardBin(rsp.getMerchantCode(), rsp.getPayeeCardNo());
		BankConfigExtPO bankconfigExt = bankConfigExtService.queryByThirdBankCode(cardBin.getBankCode(), merchant.getPaymentCode());
		payOut.setBankNo(bankconfigExt.getBankNoExt());
		payOut.setAccntNo(rsp.getPayeeCardNo());
		payOut.setAccntName(rsp.getPayeeName());
		payOut.setAmt(String.valueOf(rsp.getAmount()));
		payOut.setEntSeq(rsp.getPayoutOrderId());
		// payOut.setMemo("");
		// payOut.setMobile("");

		PayoutOrderFuiouParams param = new PayoutOrderFuiouParams();
		param.setReqType(ext.getPayOutReqType());
		param.setMerchantId(ext.getMerchantId());
		param.setMerchantSecurit(ext.getMerchantSecurit());
		param.setPayOutReqData(payOut);
		param.setUrl(ext.getUrl());
		param.setMerchantCode(merchant.getMerchantCode());
		return param;
	}

	/**
	 * 获取商户的Ext信息对象
	 *
	 * @param MerchantPaymentPO
	 * @return
	 * @throws Exception
	 */
	private FuiouPayOutExtConstant getPayOutExt(MerchantPaymentPO merchant) throws Exception {
		FuiouPayOutExtConstant ext = null;
		if (StringUtils.isNotBlank(merchant.getExt())) {
			ext = JacksonUtil.nonullMapper.fromJson(merchant.getExt(), FuiouPayOutExtConstant.class);
		} else {
			logger.error("【lianlian】【pay】支付商户扩展信息为空,merchantCode:{}", merchant.getMerchantCode());
			throw new YYPayException(PayRspCodeEnum.PAY_CODE_PAY_FAIL.getValue(), "支付商户扩展信息为空");
		}
		return ext;
	}

	@Override
	public <C extends Content> PayoutOrderYYContent transformPayoutOrderContent(C rsp) {
		PayoutOrderYYContent payoutOrderYYContent = new PayoutOrderYYContent();

		PayoutOrderFuiouContent content = (PayoutOrderFuiouContent) rsp;
		// 支付结果
		String retCode = content.getRet();
		String retMsg = content.getMemo();

		if (retCode.equals(PayoutOrderFuiouContent.SUCCESS)) {
			payoutOrderYYContent.setResultCode(PayRspCodeEnum.SUCCESS.getValue());
			payoutOrderYYContent.setResultMsg(retMsg);
		} else {
			payoutOrderYYContent.setResultCode(COMMON_ERROR_UNKNOWN_EXCEPTION.getValue());
			payoutOrderYYContent.setResultMsg(retMsg);
		}

		payoutOrderYYContent.setReqContent(content.getReqContent());
		payoutOrderYYContent.setRspContent(content.toString());
		return payoutOrderYYContent;
	}

	@Override
	public <P extends Params> P transformQueryBatchPayoutOrderParams(QueryBatchPayoutOrderYYParams rsp) {
		throw new NotImplementedException("富友支付不支持");
	}

	@Override
	public <C extends Content> QueryBatchPayoutOrderYYContent transformQueryBatchPayoutOrderContent(C req) {
		throw new NotImplementedException("富友支付不支持");
	}

	@Override
	public <P extends Params> P transformSendAuthenticationVerifyCodeParams(SendAuthenticationVerifyCodeYYParams rsp) {
		throw new NotImplementedException("富友支付不支持");
	}

	@Override
	public <C extends Content> SendAuthenticationVerifyCodeYYContent transformSendAuthenticationVerifyCodeContent(C req) {
		throw new NotImplementedException("富友支付不支持");
	}

	@SuppressWarnings({ "unchecked" })
	@Override
	public <P extends Params> P transformSendVerifyCodeParams(SendVerifyCodeYYParams req) throws Exception {
		logger.debug("【pay】【FUIOU】发送验证码请求参数:{}", JacksonUtil.nonullMapper.toJson(req));
		try {
			FuiouExtConstant fuiouConstan = fuiouPayInfoService.getMerchantInfo(FuiouExtConstant.class, req.getMerchantCode(), PaymentEnum.FUIOU,
					PayTypeEnum.PAY, PayModeEnum.AUTH_PAY);

			OrderReqData orderReqData = new OrderReqData();
			orderReqData.setVersion(fuiouConstan.getVersion());
			orderReqData.setMchntcd(fuiouConstan.getMerchantId());// 商户代码
			orderReqData.setType(fuiouConstan.getType());// 交易类型
			orderReqData.setMchntorderid(req.getPayOrderId());
			orderReqData.setUserid(req.getUserId());
			orderReqData.setAmt(req.getAmount() + "");
			orderReqData.setBankcard(req.getCardNo());
			orderReqData.setName(req.getName());
			// orderReqData.setBackurl(fuiouConstan.getBackUrl());// 通知地址
			orderReqData.setBackurl(payConstants.getNotifyUrl(PaymentEnum.FUIOU.getValue()));// 通知地址
			orderReqData.setIdtype(fuiouConstan.getIdType());
			orderReqData.setIdno(req.getIdNo());
			orderReqData.setMobile(req.getPhone());
			orderReqData.setSigntp(fuiouConstan.getSignType());
			orderReqData.setUserip(req.getUserIp());

			String signPlain = new StringBuffer().append(orderReqData.getType()).append("|").append(orderReqData.getVersion()).append("|")
					.append(orderReqData.getMchntcd()).append("|").append(orderReqData.getMchntorderid()).append("|").append(orderReqData.getUserid())
					.append("|").append(orderReqData.getAmt()).append("|").append(orderReqData.getBankcard()).append("|")
					.append(orderReqData.getBackurl()).append("|").append(orderReqData.getName()).append("|").append(orderReqData.getIdno())
					.append("|").append(orderReqData.getIdtype()).append("|").append(orderReqData.getMobile()).append("|")
					.append(orderReqData.getUserip()).append("|").append(fuiouConstan.getMerchantSecurit()).toString();
			logger.debug("【pay】【FUIOU】获取验证码sign:{}", signPlain);

			String sign = MD5.MD5Encode(signPlain);
			orderReqData.setSign(sign);
			logger.debug("【pay】【FUIOU】获取验证码请求xml:{}", JSON.toJSONString(orderReqData));

			// 请求参数加密
			Map<String, String> param = new HashMap<String, String>();
			param.put("MCHNTCD", fuiouConstan.getMerchantId());
			param.put("APIFMS", DESCoderFUIOU.desEncrypt(orderReqData.toXml(), DESCoderFUIOU.getKeyLength8(fuiouConstan.getMerchantSecurit())));

			// 日志请求参数明文
			Map<String, String> logParams = new HashMap<String, String>();
			logParams.put("MCHNTCD", fuiouConstan.getMerchantId());
			logParams.put("APIFMS", orderReqData.toXml());

			PlaceOrderFuiouParams placeOrderFuiouParams = new PlaceOrderFuiouParams();
			placeOrderFuiouParams.setUserId(req.getUserId());
			placeOrderFuiouParams.setUrl(fuiouConstan.getSendCodeUrl());
			placeOrderFuiouParams.setParams(param);
			placeOrderFuiouParams.setMerchantSecurit(fuiouConstan.getMerchantSecurit());
			placeOrderFuiouParams.setLogParams(logParams);

			return (P) placeOrderFuiouParams;
		} catch (Exception e) {
			logger.error("【pay】【FUIOU】验证码请求参数封装出错！orderId:" + req.getPayOrderId(), e);
			throw new YYPayException(PayRspCodeEnum.COMMON_ERROR_UNKNOWN_EXCEPTION, "验证码请求参数封装失败！");
		}
	}

	@Override
	public <C extends Content> SendVerifyCodeYYContent transformSendVerifyCodeContent(C rsp) throws Exception {
		PlaceOrderFuiouContent content = (PlaceOrderFuiouContent) rsp;
		try {
			SendVerifyCodeYYContent sendVerifyCodeYYContent = new SendVerifyCodeYYContent();
			if (content == null) {
				sendVerifyCodeYYContent.setResultCode(PayRspCodeEnum.PAY_CODE_PAY_FAIL.getValue());
				return sendVerifyCodeYYContent;
			}
			logger.info("【pay】【FUIOU】发送验证码响应参数:{}", content.toString());

			// 支付id解析
			PayBusiIdVO payOrderIdVo = CommonIdUtils.getPayBusiIdVo(content.getMchntorderid());
			FuiouExtConstant fuiouConstan = fuiouPayInfoService.getMerchantInfo(FuiouExtConstant.class, payOrderIdVo.getMerchantCode(),
					PaymentEnum.FUIOU, PayTypeEnum.PAY, PayModeEnum.AUTH_PAY);

			// 验签
			if (validateSign(content, fuiouConstan)) {
				if (FuiouRespConstant.RESPONSECODE_SUCCESS.equals(content.getResponsecode())) {
					logger.info("【pay】【FUIOU】订单号：{}，获取支付验证码成功！", content.getMchntorderid());
					sendVerifyCodeYYContent.setResultCode(PayRspCodeEnum.SUCCESS.getValue());
					sendVerifyCodeYYContent.setToken(content.getSignpay());
				} else {
					logger.info("【pay】【FUIOU】订单号：{}，获取支付验证码失败！result:{}", content.getMchntorderid(), content.toString());
					sendVerifyCodeYYContent.setResultCode(PayRspCodeEnum.PAY_CODE_GET_PAY_VERIFY_CODE_FAIL.getValue());
				}

				// 响应信息具体
				sendVerifyCodeYYContent.setResultMsg(content.getResponsemsg());
				sendVerifyCodeYYContent.setPayOrderId(content.getMchntorderid());
			} else {
				sendVerifyCodeYYContent.setResultCode(PayRspCodeEnum.PAY_CODE_CHECK_SIGN_FAIL.getValue());
				sendVerifyCodeYYContent.setResultMsg("获取验证码验签失败");
				logger.error("【pay】【FUIOU】获取验证码验签失败！orderId:{}", content.getMchntorderid());
			}

			sendVerifyCodeYYContent.setSerialNo(content.getOrderid());
			sendVerifyCodeYYContent.setRspContent(content.getRsqContent());

			return sendVerifyCodeYYContent;
		} catch (Exception e) {
			logger.error("【pay】【FUIOU】验证码响应处理出错！orderId:" + content, e);
			throw new YYPayException(PayRspCodeEnum.COMMON_ERROR_UNKNOWN_EXCEPTION, "验证码响应处理失败！");
		}
	}

	// /**
	// * 根据商户号获取商户支付信息
	// *
	// * @author heizq
	// * @date 2017-04-13 14:12:04
	// * @since v1.0.0
	// * @param fuiouConstan 商户支付扩展信息
	// * @param merchantId 商户号
	// * @param merchantCode 商户编号
	// */
	// public FuiouExtConstant getFuiouMerchantInfo(String merchantCode) throws Exception {
	// MerchantPaymentPO merchant = merchantPaymentService.queryByThirdMerchantCode(merchantCode, PaymentEnum.FUIOU.getValue(),
	// PayTypeEnum.PAY.getValue(), PayModeEnum.AUTH_PAY.getValue());
	// FuiouExtConstant fuiouConstan = null;
	// if (merchant == null) {
	// logger.error("【pay】【FUIOU】查询支付通过信息失败,商户信息为空,merchantCode:{}", merchantCode);
	// throw new YYPayException(RspCodeEnum.COMMON_ERROR_OBJECT_NOT_FOUND.getValue(), "查询支付通过信息失败,商户信息为空.");
	// }
	// if (StringUtils.isNotBlank(merchant.getExt())) {
	// fuiouConstan = JacksonUtil.nonullMapper.fromJson(merchant.getExt(), FuiouExtConstant.class);
	// } else {
	// logger.error("【pay】【FUIOU】支付商户扩展信息为空,merchantCode:{}", merchantCode);
	// throw new YYPayException(RspCodeEnum.COMMON_ERROR_OBJECT_NOT_FOUND.getValue(), "支付通过扩展信息为空");
	// }
	// logger.info("【pay】【FUIOU】查询支付通过信息成功,merchant:{}", JacksonUtil.nonullMapper.toJson(merchant));
	// fuiouConstan.setMerchantId(merchant.getPayMerchantId());
	// return fuiouConstan;
	// }

	@SuppressWarnings("unchecked")
	@Override
	public FuiouBaseReqVO transformQueryCardBinParams(QueryCardBinParams req) throws Exception {
		// 转换请求参数
		FuiouExtConstant fuiouConstant = fuiouPayInfoService.getMerchantInfo(FuiouExtConstant.class, req.getMerchantCode(), PaymentEnum.FUIOU,
				PayTypeEnum.CARD_BIN, PayModeEnum.AUTH_PAY);

		CardBinReq xml = new CardBinReq();
		xml.setMchntcd(fuiouConstant.getMerchantId());
		xml.setoNo(req.getCardNo());
		// xml.setSign(transformName);

		StringBuilder signSrc = new StringBuilder().append(xml.getMchntcd()).append("|").append(xml.getoNo()).append("|")
				.append(fuiouConstant.getMerchantSecurit());
		String sign = MD5.MD5Encode(signSrc.toString());
		xml.setSign(sign);

		Map<String, String> map = Maps.newHashMap();
		map.put("FM", xml.toXml());

		FuiouBaseReqVO vo = new FuiouBaseReqVO();
		vo.setUrl(fuiouConstant.getCardBinUrl());
		vo.setReqBody(xml.toXml());
		vo.setActReqBody(map);

		return vo;
	}

	@Override
	public <C> QueryCardBinContent transformQueryCardBinContent(C req) throws Exception {
		QueryCardBinContent content = new QueryCardBinContent();
		String rspStr = (String) req;

		if (StringUtils.isBlank(rspStr)) {
			throw new YYPayException(PayRspCodeEnum.PAY_CODE_QUERY_CARD_BIN_ERROR, "查询卡bin返回null");
		}

		CardBinRsp rsp = CardBinRsp.fromXml(rspStr);

		if (StringUtils.equals(FuiouRespConstant.CARD_BIN_NOT_SUPPORT, rsp.getRcd())) {
			// 如果应答码为不支持的银行
			content.setResultCode(PayRspCodeEnum.PAY_CODE_BANK_NOT_SUPPORT.getValue());
			content.setResultMsg(rsp.getrDesc());
			return content;
		}

		if (!StringUtils.equals(FuiouRespConstant.RESPONSECODE_SUCCESS, rsp.getRcd())) {
			// 如果应答码不是成功状态
			content.setResultCode(PayRspCodeEnum.PAY_CODE_QUERY_CARD_BIN_ERROR.getValue());
			content.setResultMsg(rsp.getrDesc());

			return content;
		}

		// 判断卡类型
		if (!StringUtils.equals(FuiouCardTypeEnum.DEBIT.getValue(), rsp.getCtp())) {
			throw new YYPayException(PayRspCodeEnum.PAY_CODE_CARD_TYPE_NOT_SUPPORT, "不支持非借记卡");
		}

		// 奇葩的富友是根据银行前六位判定是否同一家银行
		String bankCode = rsp.getInsCd().substring(0, 6);

		BankConfigPO bankConfigPO = bankConfigService.queryByThirdBankCode(PaymentEnum.FUIOU.getValue(), bankCode);
		if (bankConfigPO == null || YesNoEnum.NO.getValue().equals(bankConfigPO.getState())) {
			throw new YYPayException(PayRspCodeEnum.PAY_CODE_BANK_NOT_SUPPORT,
					"缺少银行配置信息,paymentCode:" + PaymentEnum.FUIOU.getValue() + ",bank_code_ext:" + rsp.getInsCd());
		}

		content.setResultCode(PayRspCodeEnum.SUCCESS.getValue());
		content.setResultMsg(rsp.getrDesc());
		content.setBankCode(bankConfigPO.getBankCode());
		content.setBankName(bankConfigPO.getBankName());
		content.setEnName(bankConfigPO.getEnName());

		return content;
	}

	/**
	 * 校验返回的签名
	 *
	 * @param noticeContent
	 * @param fuiouConstant
	 * @return
	 * @author heizq
	 * @date 2017-04-16 11:36:30
	 * @since v1.0.0
	 */
	public boolean validateSign(Content content, FuiouExtConstant fuiouConstant) {
		String signPain = "";
		PlaceOrderFuiouContent placeOrderFuiouContent = null;
		PayOrderFuiouContent payOrderFuiouContent = null;
		PayOrderNoticeFuiouContent noticeContent = null;
		QueryOrderByOrderNumFuiouContent queryPayOrderContent = null;
		WithoutVerifyFuiouContent withoutVerifyFuiouContent;

		// 获取验证码
		if (content instanceof PlaceOrderFuiouContent) {
			placeOrderFuiouContent = (PlaceOrderFuiouContent) content;
			signPain = new StringBuffer().append(placeOrderFuiouContent.getType()).append("|").append(placeOrderFuiouContent.getVersion()).append("|")
					.append(placeOrderFuiouContent.getResponsecode()).append("|").append(placeOrderFuiouContent.getMchntcd()).append("|")
					.append(placeOrderFuiouContent.getMchntorderid()).append("|").append(placeOrderFuiouContent.getUserid()).append("|")
					.append(placeOrderFuiouContent.getOrderid()).append("|").append(placeOrderFuiouContent.getAmt()).append("|")
					.append(fuiouConstant.getMerchantSecurit()).toString();
			logger.debug("【pay】【FUIOU】获取验证码返回加密前签名，sign：{}", signPain);
			if (MD5.MD5Encode(signPain).equals(placeOrderFuiouContent.getSign())) {
				return true;
			}
		}
		// 支付
		if (content instanceof PayOrderFuiouContent) {
			payOrderFuiouContent = (PayOrderFuiouContent) content;
			signPain = new StringBuffer().append(payOrderFuiouContent.getType()).append("|").append(payOrderFuiouContent.getVersion()).append("|")
					.append(payOrderFuiouContent.getResponsecode()).append("|").append(payOrderFuiouContent.getMchntcd()).append("|")
					.append(payOrderFuiouContent.getMchntorderid()).append("|").append(payOrderFuiouContent.getOrderid()).append("|")
					.append(payOrderFuiouContent.getAmt()).append("|").append(payOrderFuiouContent.getBankcard()).append("|")
					.append(fuiouConstant.getMerchantSecurit()).toString();
			logger.debug("【pay】【FUIOU】支付返回加密前签名，sign：{}", signPain);
			if (MD5.MD5Encode(signPain).equals(payOrderFuiouContent.getSign())) {
				return true;
			}
		}
		// 异步回调
		if (content instanceof PayOrderNoticeFuiouContent) {
			noticeContent = (PayOrderNoticeFuiouContent) content;
			signPain = new StringBuffer().append(noticeContent.getType()).append("|").append(noticeContent.getVersion()).append("|")
					.append(noticeContent.getResponsecode()).append("|").append(noticeContent.getMchntcd()).append("|")
					.append(noticeContent.getMchntorderid()).append("|").append(noticeContent.getOrderid()).append("|").append(noticeContent.getAmt())
					.append("|").append(noticeContent.getBankcard()).append("|").append(fuiouConstant.getMerchantSecurit()).toString();
			logger.debug("【pay】【FUIOU】异步通知加密前签名，sign：{}", signPain);
			if (MD5.MD5Encode(signPain).equals(noticeContent.getSign())) {
				return true;
			}
		}
		// 根据平台订单查单
		if (content instanceof QueryOrderByOrderNumFuiouContent) {
			queryPayOrderContent = (QueryOrderByOrderNumFuiouContent) content;
			signPain = new StringBuffer().append(queryPayOrderContent.getVersion()).append("|").append(queryPayOrderContent.getResponseCode())
					.append("|").append(queryPayOrderContent.getResponseMsg()).append("|").append(queryPayOrderContent.getMchntOrderId()).append("|")
					.append(fuiouConstant.getMerchantSecurit()).toString();
			if (MD5.MD5Encode(signPain).equals(queryPayOrderContent.getSign())) {
				return true;
			}
		}

		// 独立鉴权
		if (content instanceof WithoutVerifyFuiouContent) {
			withoutVerifyFuiouContent = (WithoutVerifyFuiouContent) content;
			signPain = new StringBuffer().append(withoutVerifyFuiouContent.getRcd()).append("|").append(withoutVerifyFuiouContent.getoSsn())
					.append("|").append(withoutVerifyFuiouContent.getCardNo()).append("|").append(withoutVerifyFuiouContent.getMchntCd()).append("|")
					.append(withoutVerifyFuiouContent.getVersion()).append("|").append(fuiouConstant.getMerchantSecurit()).toString();
			logger.debug("【pay】【FUIOU】获取独立鉴权返回加密前签名，sign：{}", signPain);
			if (MD5.MD5Encode(signPain).equals(withoutVerifyFuiouContent.getSign())) {
				return true;
			}
		}
		return false;
	}

	@SuppressWarnings("unchecked")
	@Override
	public <P extends Params> P transformQueryPayOutOrderParams(QueryPayoutOrderYYParams rsp) throws Exception {
		// 获取富友商户代付信息
		MerchantPaymentPO merchant = merchantPaymentService.queryByThirdMerchantCode(rsp.getMerchantCode(), PaymentEnum.FUIOU.getValue(),
				PayTypeEnum.PAY_OUT.getValue(), PayModeEnum.AUTH_PAY.getValue());
		logger.info("【富友】【pay】查询支付通过信息成功,merchant:{}", JacksonUtil.nonullMapper.toJson(merchant));
		if (merchant == null) {
			logger.error("【富友】【pay】查询支付通过信息失败,商户信息为空,merchantCode:{}", rsp.getMerchantCode());
			//throw new YYPayException(PayRspCodeEnum.PAY_CODE_PAY_FAIL.getValue(), "查询支付通过信息失败,商户信息为空.");
			throw new YYPayException(PayRspCodeEnum.PAY_CODE_MERCHANT_CONFIG_ILLEGAL);
		}
		return (P) buildPayOutOrderQueryFuiouParams(merchant, rsp);
	}

	/**
	 * 根据商户信息和代付订单，构建代付查询请求对象
	 *
	 * @param merchant
	 * @param rsp
	 * @return
	 * @throws Exception
	 */
	private QueryPayoutOrderFuiouParams buildPayOutOrderQueryFuiouParams(MerchantPaymentPO merchant, QueryPayoutOrderYYParams rsp) throws Exception {
		String fuiouOrderNo = rsp.getPayoutOrderId().substring(2);
		if (!NumberUtils.isDigits(fuiouOrderNo)) {
			throw new YYPayException(PayRspCodeEnum.COMMON_ERROR_PARAMETER_INVALID, "富友订单号必须为纯数字,订单号是:" + rsp.getPayoutOrderId());
		}
		QueryPayoutOrderFuiouParams param = new QueryPayoutOrderFuiouParams();
		FuiouPayOutExtConstant ext = getPayOutExt(merchant);
		param.setReqType(ext.getQryReqType());
		QueryPayoutReqData query = new QueryPayoutReqData();
		query.setVer(ext.getVersion());
		query.setBusicd(QueryPayoutReqData.PAY_OUT_CODE);
		query.setOrderno(fuiouOrderNo);
		query.setStartdt(rsp.getOrderTime().substring(0, 10).replaceAll("-", ""));
		query.setEnddt(rsp.getOrderTime().substring(0, 10).replaceAll("-", ""));
		param.setMerchantId(merchant.getPayMerchantId());
		param.setMerchantSecurit(ext.getMerchantSecurit());
		param.setQueryPayoutReqData(query);
		param.setUrl(ext.getUrl());
		param.setMerchantCode(merchant.getMerchantCode());
		param.setQueryPayoutReqData(query);
		return param;
	}

	@Override
	public <C extends Content> QueryPayoutOrderYYContent transformQueryPayOutOrderContent(C rsp) throws Exception {
		QueryPayoutOrderYYContent content = new QueryPayoutOrderYYContent();
		QueryPayoutOrderFuiouContent fuiouContent = (QueryPayoutOrderFuiouContent) rsp;
		// 支付结果
		List<QueryTransContent> trans = fuiouContent.getTrans();
		/**
		 * 查询state含义：
		 * 0--交易未发送
		 * 1--交易已发送且成功(扣款成功)
		 * 2--交易已发送且失败(扣款失败)
		 * 3--交易发送中
		 **/
		if (CollectionUtils.isNotEmpty(trans)) {
			// 根据订单查询，最多只有一条记录
			QueryTransContent item = trans.get(0);
			String state = item.getState();

			if (FuiouPayoutStateEnum.UN_SEND.isValue(state)) {
				content.setResultCode(PayRspCodeEnum.PAY_CODE_PAYOUT_NO_SEND.getValue());
				content.setResultMsg(PayRspCodeEnum.PAY_CODE_PAYOUT_NO_SEND.getDisplay());
			} else if (FuiouPayoutStateEnum.SUCCESS.isValue(state)) {
				content.setResultCode(PayRspCodeEnum.SUCCESS.getValue());
				content.setResultMsg(PayRspCodeEnum.SUCCESS.getDisplay());
			} else if (FuiouPayoutStateEnum.FAIL.isValue(state)) {
				content.setResultCode(PayRspCodeEnum.PAY_CODE_PAY_FAIL.getValue());
				content.setResultMsg(PayRspCodeEnum.PAY_CODE_PAY_FAIL.getDisplay());
			} else if (FuiouPayoutStateEnum.DEALING.isValue(state)) {
				content.setResultCode(PayRspCodeEnum.PAY_CODE_DEALING.getValue());
				content.setResultMsg(PayRspCodeEnum.PAY_CODE_DEALING.getDisplay());
			} else {
				content.setResultCode(PAY_CODE_QUERY_ORDER_FAIL.getValue());
				content.setResultMsg(PAY_CODE_QUERY_ORDER_FAIL.getDisplay());
			}

			content.setOrderId(item.getOrderno());
			content.setAmount(Integer.valueOf(item.getAmt()));
		} else {
			content.setResultCode(PAY_CODE_QUERY_ORDER_FAIL.getValue());
			content.setResultMsg(fuiouContent.getMemo());
		}

		content.setReqContent(fuiouContent.getReqContent());
		content.setRspContent(fuiouContent.toString());
		return content;
	}

	@Override
	public <P extends Params> P transformWithoutVerifyParams(WithoutVerifyYYParams req) throws Exception {
		try {
			logger.debug("【pay】【FUIOU】查单请求参数:{}", JacksonUtil.nonullMapper.toJson(req));

			FuiouExtConstant fuiouConstan = fuiouPayInfoService.getMerchantInfo(FuiouExtConstant.class, req.getMerchantCode(), PaymentEnum.FUIOU,
					PayTypeEnum.AUTH, PayModeEnum.AUTH_PAY);

			String merchantCd = fuiouConstan.getMerchantId();
			String version = fuiouConstan.getVersion();
			String ossn = req.getOrderId();
			String ono = req.getCardNo();
			String onm = req.getName();

			// 身份证号,需要修改
			String oCerTp = "0";
			String oCerNo = req.getIdNo();
			String mno = req.getPhone();

			String sign = MD5
					.MD5Encode(new StringBuffer().append(merchantCd).append("|").append(version).append("|").append(ossn).append("|").append(ono)
							.append("|").append(oCerTp).append("|").append(oCerNo).append("|").append(fuiouConstan.getMerchantSecurit()).toString());

			QueryPayWithoutVerifyData queryPayWithoutVerifyData = new QueryPayWithoutVerifyData();
			queryPayWithoutVerifyData.setVersion(version);
			queryPayWithoutVerifyData.setMchntcd(merchantCd);
			queryPayWithoutVerifyData.setOno(ono);
			queryPayWithoutVerifyData.setoSsn(ossn);
			queryPayWithoutVerifyData.setOnm(onm);
			queryPayWithoutVerifyData.setMno(mno);
			queryPayWithoutVerifyData.setoCerNo(oCerNo);
			queryPayWithoutVerifyData.setoCerTp(oCerTp);
			queryPayWithoutVerifyData.setSign(sign);

			String fm = queryPayWithoutVerifyData.toXml();
			logger.info("【pay】【FUIOU】商户编号：{}，请求xml:{}", merchantCd, fm);

			Map<String, String> params = new HashMap<>();
			params.put("FM", fm);

			WithoutVerifyFuiouParams withoutVerifyFuiouParams = new WithoutVerifyFuiouParams();
			withoutVerifyFuiouParams.setUrl(fuiouConstan.getAuthUrl());
			withoutVerifyFuiouParams.setParams(params);
			withoutVerifyFuiouParams.setReqBody(fm);
			withoutVerifyFuiouParams.setUserId(req.getUserId());
			withoutVerifyFuiouParams.setMerchantSecurit(fuiouConstan.getMerchantSecurit());
			return (P) withoutVerifyFuiouParams;
		} catch (Exception e) {
			logger.error("【pay】【FUIOU】查单请求封装出错！orderId:" + req.getOrderId(), e);
			throw new YYPayException(PayRspCodeEnum.COMMON_ERROR_UNKNOWN_EXCEPTION, "查单请求参数封装失败！");
		}
	}

	@Override
	public <C extends Content> WithoutVerifyYYContent transformWithoutVerifyContent(C req) throws Exception {
		WithoutVerifyFuiouContent content = (WithoutVerifyFuiouContent) req;
		try {
			WithoutVerifyYYContent withoutVerifyYYContent = new WithoutVerifyYYContent();
			if (content == null) {
				withoutVerifyYYContent.setResultCode(PayRspCodeEnum.PAY_CODE_PAY_FAIL.getValue());
				return withoutVerifyYYContent;
			}
			logger.info("【pay】【FUIOU】独立鉴权响应参数:{}", content.toString());

			// 支付id解析
			FuiouExtConstant fuiouConstan = fuiouPayInfoService.getMerchantInfo(FuiouExtConstant.class, content.getMerchentId(), PaymentEnum.FUIOU,
					PayTypeEnum.AUTH, PayModeEnum.AUTH_PAY);

			// 验签
			if (validateSign(content, fuiouConstan)) {
				if (FuiouRespConstant.RESPONSECODE_SUCCESS.equals(content.getRcd())) {
					logger.info("【pay】【FUIOU】商户代码：{}，获取独立鉴权成功！", content.getMchntCd());
					withoutVerifyYYContent.setResultCode(PayRspCodeEnum.SUCCESS.getValue());
				} else {
					logger.info("【pay】【FUIOU】商户代码：{}，获取独立鉴权失败！result:{}", content.getMchntCd(), content.toString());
					withoutVerifyYYContent.setResultCode(PayRspCodeEnum.PAY_CODE_GET_PAY_WITHOUT_VERIFY_FAIL.getValue());
				}
				// 响应信息具体
				withoutVerifyYYContent.setResultMsg(content.getrDesc());
			} else {
				withoutVerifyYYContent.setResultCode(PayRspCodeEnum.PAY_CODE_GET_PAY_WITHOUT_VERIFY_FAIL.getValue());
				withoutVerifyYYContent.setResultMsg("获取独立鉴权失败");
				logger.error("【pay】【FUIOU】获取独立鉴权失败！MchntCd:{}", content.getMchntCd());
			}

			return withoutVerifyYYContent;
		} catch (Exception e) {
			logger.error("【pay】【FUIOU】独立鉴权响应处理出错！MchntCd:" + content, e);
			throw new YYPayException(PayRspCodeEnum.COMMON_ERROR_UNKNOWN_EXCEPTION, "独立鉴权处理失败！");
		}
	}

	/**
	 * 首次协议支付获取验证码参数转换
	 *
	 * @param req
	 * @return
	 * @throws Exception
	 * @author heizq
	 * @date 2017-05-12 09:32:56
	 * @since v1.2.0
	 */
	public <P extends Params> P transformProtocolSendVerifyCodeParams(SendVerifyCodeYYParams req) throws Exception {
		try {
			logger.debug("【pay】【FUIOU】发送验证码请求参数:{}", JSON.toJSONString(req));

			FuiouExtConstant fuiouConstan = fuiouPayInfoService.getMerchantInfo(FuiouExtConstant.class, req.getMerchantCode(), PaymentEnum.FUIOU,
					PayTypeEnum.PAY, PayModeEnum.AUTH_PAY);

			ProtocolOrderReqData orderReqData = new ProtocolOrderReqData();
			orderReqData.setVersion(fuiouConstan.getProtocolVersion());
			orderReqData.setMchntcd(fuiouConstan.getMerchantId());// 商户代码
			orderReqData.setType(fuiouConstan.getType());// 交易类型
			orderReqData.setMchntorderid(req.getPayOrderId());
			orderReqData.setUserid(req.getUserId());
			orderReqData.setAmt(req.getAmount() + "");
			orderReqData.setBankcard(req.getCardNo());
			orderReqData.setName(req.getName());
			orderReqData.setBackurl(fuiouConstan.getProtocolBackUrl());// 通知地址
			orderReqData.setIdtype(fuiouConstan.getIdType());
			orderReqData.setIdno(req.getIdNo());
			orderReqData.setMobile(req.getPhone());
			orderReqData.setSigntp(fuiouConstan.getSignType());
			orderReqData.setUserip(req.getUserIp());

			String signPlain = FuiouSignUtil.createFuiouSign(orderReqData, fuiouConstan.getMerchantSecurit());
			logger.debug("【pay】【FUIOU】获取验证码sign:{}", signPlain);

			orderReqData.setSign(signPlain);
			logger.info("【pay】【FUIOU】首次协议支付获取验证码,订单信息:{}", orderReqData.toXml());

			Map<String, String> param = new HashMap<String, String>();
			param.put("MCHNTCD", fuiouConstan.getMerchantId());
			param.put("APIFMS", DESCoderFUIOU.desEncrypt(orderReqData.toXml(), DESCoderFUIOU.getKeyLength8(fuiouConstan.getMerchantSecurit())));

			Map<String, String> logParam = new HashMap<String, String>();
			logParam.put("MCHNTCD", fuiouConstan.getMerchantId());
			logParam.put("APIFMS", orderReqData.toXml());

			ProtocolPlaceOrderFuiouParams placeOrderFuiouParams = new ProtocolPlaceOrderFuiouParams();
			placeOrderFuiouParams.setMerchantSecurit(fuiouConstan.getMerchantSecurit());
			placeOrderFuiouParams.setUrl(fuiouConstan.getSendFirstCodeUrl());
			placeOrderFuiouParams.setUserId(req.getUserId());
			placeOrderFuiouParams.setParams(param);
			placeOrderFuiouParams.setLogParams(logParam);

			return (P) placeOrderFuiouParams;
		} catch (Exception e) {
			logger.error("【pay】【FUIOU】验证码请求参数封装出错！orderId:" + req.getPayOrderId(), e);
			throw new YYPayException(PayRspCodeEnum.COMMON_ERROR_UNKNOWN_EXCEPTION, "验证码请求参数封装失败！");
		}
	}

	/**
	 * 首次协议支付获取验证码响应转换
	 *
	 * @param rsp
	 * @return
	 * @throws Exception
	 * @author heizq
	 * @date 2017-05-12 09:59:02
	 * @since v1.2.0
	 */
	public <C extends Content> SendVerifyCodeYYContent transformProtocolSendVerifyCodeContent(C rsp) throws Exception {
		ProtocolPlaceOrderFuiouContent content = (ProtocolPlaceOrderFuiouContent) rsp;
		try {
			SendVerifyCodeYYContent sendVerifyCodeYYContent = new SendVerifyCodeYYContent();
			if (content == null) {
				sendVerifyCodeYYContent.setResultCode(PayRspCodeEnum.PAY_CODE_PAY_FAIL.getValue());
				return sendVerifyCodeYYContent;
			}
			logger.info("【pay】【FUIOU】发送验证码响应参数:{}", content.toString());

			// 支付id解析
			PayBusiIdVO payOrderIdVo = CommonIdUtils.getPayBusiIdVo(content.getMchntorderid());
			FuiouExtConstant fuiouConstan = fuiouPayInfoService.getMerchantInfo(FuiouExtConstant.class, payOrderIdVo.getMerchantCode(),
					PaymentEnum.FUIOU, PayTypeEnum.PAY, PayModeEnum.AUTH_PAY);

			// 验签
			if (FuiouSignUtil.checkFuiouSign(content, content.getSign(), fuiouConstan.getMerchantSecurit())) {
				if (FuiouRespConstant.RESPONSECODE_SUCCESS.equals(content.getResponsecode())) {
					logger.info("【pay】【FUIOU】订单号：{}，获取支付验证码成功！", content.getMchntorderid());
					sendVerifyCodeYYContent.setResultCode(PayRspCodeEnum.SUCCESS.getValue());
					sendVerifyCodeYYContent.setToken(content.getSignpay());
				} else {
					logger.info("【pay】【FUIOU】订单号：{}，获取支付验证码失败！result:{}", content.getMchntorderid(), content.toString());
					sendVerifyCodeYYContent.setResultCode(PayRspCodeEnum.PAY_CODE_GET_PAY_VERIFY_CODE_FAIL.getValue());
				}

				// 响应信息具体
				sendVerifyCodeYYContent.setResultMsg(content.getResponsemsg());
				sendVerifyCodeYYContent.setPayOrderId(content.getMchntorderid());
			} else {
				sendVerifyCodeYYContent.setResultCode(PayRspCodeEnum.PAY_CODE_CHECK_SIGN_FAIL.getValue());
				sendVerifyCodeYYContent.setResultMsg("获取验证码验签失败");
				logger.error("【pay】【FUIOU】获取验证码验签失败！orderId:{}", content.getMchntorderid());
			}

			sendVerifyCodeYYContent.setSerialNo(content.getOrderid());
			sendVerifyCodeYYContent.setUserId(content.getUserid());
			sendVerifyCodeYYContent.setReqUrl(fuiouConstan.getSendFirstCodeUrl());
			sendVerifyCodeYYContent.setRspContent(content.getRspContent());

			return sendVerifyCodeYYContent;
		} catch (Exception e) {
			logger.error("【pay】【FUIOU】验证码响应处理出错！orderId:" + content, e);
			throw new YYPayException(PayRspCodeEnum.COMMON_ERROR_UNKNOWN_EXCEPTION, "验证码响应处理失败！");
		}
	}

	/**
	 * 首次协议支付获取验证码重发参数转换
	 *
	 * @param req
	 * @return
	 * @throws Exception
	 * @author heizq
	 * @date 2017-05-12 09:32:56
	 * @since v1.2.0
	 */
	public <P extends Params> P transformProtocolRetrySendVerifyCodeParams(SendVerifyCodeYYParams req) throws Exception {
		try {
			logger.debug("【pay】【FUIOU】发送验证码请求参数:{}", JSON.toJSONString(req));

			FuiouExtConstant fuiouConstan = fuiouPayInfoService.getMerchantInfo(FuiouExtConstant.class, req.getMerchantCode(), PaymentEnum.FUIOU,
					PayTypeEnum.PAY, PayModeEnum.AUTH_PAY);

			ProtocolOrderRetryReqData orderReqData = new ProtocolOrderRetryReqData();
			orderReqData.setVersion(fuiouConstan.getProtocolVersion());
			orderReqData.setMchntcd(fuiouConstan.getMerchantId());// 商户代码
			orderReqData.setType(fuiouConstan.getType());// 交易类型
			orderReqData.setUserid(req.getUserId());
			orderReqData.setAmt(req.getAmount() + "");
			orderReqData.setBankcard(req.getCardNo());
			orderReqData.setName(req.getName());
			orderReqData.setBackurl(fuiouConstan.getProtocolBackUrl());// 通知地址
			orderReqData.setIdtype(fuiouConstan.getIdType());
			orderReqData.setIdno(req.getIdNo());
			orderReqData.setMobile(req.getPhone());
			orderReqData.setSigntp(fuiouConstan.getSignType());
			orderReqData.setUserip(req.getUserIp());
			orderReqData.setOrderId(req.getSerialNo());// 这里需要传入富友订单号

			String signPlain = FuiouSignUtil.createFuiouSign(orderReqData, fuiouConstan.getMerchantSecurit());
			logger.debug("【pay】【FUIOU】获取验证码sign:{}", signPlain);

			orderReqData.setSign(signPlain);
			logger.info("【pay】【FUIOU】首次协议支付获取验证码,订单信息:{}", JSON.toJSONString(orderReqData));

			Map<String, String> param = new HashMap<String, String>();
			param.put("MCHNTCD", fuiouConstan.getMerchantId());
			param.put("APIFMS", DESCoderFUIOU.desEncrypt(orderReqData.toXml(), DESCoderFUIOU.getKeyLength8(fuiouConstan.getMerchantSecurit())));

			Map<String, String> logParam = new HashMap<String, String>();
			logParam.put("MCHNTCD", fuiouConstan.getMerchantId());
			logParam.put("APIFMS", orderReqData.toXml());

			ProtocolPlaceOrderRetryFuiouParams placeOrderFuiouParams = new ProtocolPlaceOrderRetryFuiouParams();
			placeOrderFuiouParams.setMerchantSecurit(fuiouConstan.getMerchantSecurit());
			placeOrderFuiouParams.setUrl(fuiouConstan.getSendCodeRetryUrl());
			placeOrderFuiouParams.setUserId(req.getUserId());
			placeOrderFuiouParams.setParams(param);
			placeOrderFuiouParams.setLogParams(logParam);

			return (P) placeOrderFuiouParams;
		} catch (Exception e) {
			logger.error("【pay】【FUIOU】验证码请求参数封装出错！orderId:" + req.getPayOrderId(), e);
			throw new YYPayException(PayRspCodeEnum.COMMON_ERROR_UNKNOWN_EXCEPTION, "验证码请求参数封装失败！");
		}
	}

	/**
	 * 首次协议支付获取验证码重发响应转换
	 *
	 * @param rsp
	 * @return
	 * @throws Exception
	 * @author heizq
	 * @date 2017-05-12 09:59:02
	 * @since v1.2.0
	 */
	public <C extends Content> SendVerifyCodeYYContent transformProtocolRetrySendVerifyCodeContent(C rsp) throws Exception {
		ProtocolPlaceOrderRetryFuiouContent content = (ProtocolPlaceOrderRetryFuiouContent) rsp;
		try {
			SendVerifyCodeYYContent sendVerifyCodeYYContent = new SendVerifyCodeYYContent();
			if (content == null) {
				sendVerifyCodeYYContent.setResultCode(PayRspCodeEnum.PAY_CODE_PAY_FAIL.getValue());
				return sendVerifyCodeYYContent;
			}
			logger.info("【pay】【FUIOU】发送验证码响应参数:{}", content.toString());

			// 支付id解析
			PayBusiIdVO payOrderIdVo = CommonIdUtils.getPayBusiIdVo(content.getMchntorderid());
			FuiouExtConstant fuiouConstan = fuiouPayInfoService.getMerchantInfo(FuiouExtConstant.class, payOrderIdVo.getMerchantCode(),
					PaymentEnum.FUIOU, PayTypeEnum.PAY, PayModeEnum.AUTH_PAY);

			// 验签
			if (FuiouSignUtil.checkFuiouSign(content, content.getSign(), fuiouConstan.getMerchantSecurit())) {
				if (FuiouRespConstant.RESPONSECODE_SUCCESS.equals(content.getResponsecode())) {
					logger.info("【pay】【FUIOU】订单号：{}，获取支付验证码成功！", content.getMchntorderid());
					sendVerifyCodeYYContent.setResultCode(PayRspCodeEnum.SUCCESS.getValue());
					sendVerifyCodeYYContent.setToken(content.getSignpay());
				} else {
					logger.info("【pay】【FUIOU】订单号：{}，获取支付验证码失败！result:{}", content.getMchntorderid(), content.toString());
					sendVerifyCodeYYContent.setResultCode(PayRspCodeEnum.PAY_CODE_GET_PAY_VERIFY_CODE_FAIL.getValue());
				}

				// 响应信息具体
				sendVerifyCodeYYContent.setResultMsg(content.getResponsemsg());
				sendVerifyCodeYYContent.setPayOrderId(content.getMchntorderid());
			} else {
				sendVerifyCodeYYContent.setResultCode(PayRspCodeEnum.PAY_CODE_CHECK_SIGN_FAIL.getValue());
				sendVerifyCodeYYContent.setResultMsg("获取验证码验签失败");
				logger.error("【pay】【FUIOU】获取验证码验签失败！orderId:{}", content.getMchntorderid());
			}

			sendVerifyCodeYYContent.setSerialNo(content.getOrderid());
			sendVerifyCodeYYContent.setReqUrl(fuiouConstan.getSendCodeRetryUrl());
			sendVerifyCodeYYContent.setRspContent(content.getRsqContent());

			return sendVerifyCodeYYContent;
		} catch (Exception e) {
			logger.error("【pay】【FUIOU】验证码响应处理出错！orderId:" + content, e);
			throw new YYPayException(PayRspCodeEnum.COMMON_ERROR_UNKNOWN_EXCEPTION, "验证码响应处理失败！");
		}
	}

	/**
	 * 再次协议支付获取验证码参数转换
	 *
	 * @param req
	 * @return
	 * @throws Exception
	 * @author heizq
	 * @date 2017-05-12 09:32:56
	 * @since v1.2.0
	 */
	public <P extends Params> P transformProtocolAgainSendVerifyCodeParams(SendVerifyCodeYYParams req) throws Exception {
		try {
			logger.debug("【pay】【FUIOU】发送验证码请求参数:{}", JSON.toJSONString(req));

			FuiouExtConstant fuiouConstan = fuiouPayInfoService.getMerchantInfo(FuiouExtConstant.class, req.getMerchantCode(), PaymentEnum.FUIOU,
					PayTypeEnum.PAY, PayModeEnum.AUTH_PAY);

			ReProtocolOrderReqData orderReqData = new ReProtocolOrderReqData();
			orderReqData.setVersion(fuiouConstan.getProtocolVersion());
			orderReqData.setMchntcd(fuiouConstan.getMerchantId());// 商户代码
			orderReqData.setType(fuiouConstan.getType());// 交易类型
			orderReqData.setUserid(req.getUserId());
			orderReqData.setAmt(req.getAmount() + "");
			orderReqData.setSigntp(fuiouConstan.getSignType());
			orderReqData.setUserip(req.getUserIp());
			orderReqData.setProtocolNo(req.getProtocolNo());
			orderReqData.setBackUrl(fuiouConstan.getProtocolBackUrl());
			orderReqData.setMchntorderid(req.getPayOrderId());

			String signPlain = FuiouSignUtil.createFuiouSign(orderReqData, fuiouConstan.getMerchantSecurit());
			logger.debug("【pay】【FUIOU】获取验证码sign:{}", signPlain);

			orderReqData.setSign(signPlain);
			logger.info("【pay】【FUIOU】首次协议支付获取验证码,订单信息:{}", JSON.toJSONString(orderReqData));

			Map<String, String> param = new HashMap<String, String>();
			param.put("MCHNTCD", fuiouConstan.getMerchantId());
			param.put("APIFMS", DESCoderFUIOU.desEncrypt(orderReqData.toXml(), DESCoderFUIOU.getKeyLength8(fuiouConstan.getMerchantSecurit())));

			Map<String, String> logParam = new HashMap<String, String>();
			logParam.put("MCHNTCD", fuiouConstan.getMerchantId());
			logParam.put("APIFMS", orderReqData.toXml());

			ProtocolPlaceOrderAgainFuiouParams placeOrderFuiouParams = new ProtocolPlaceOrderAgainFuiouParams();
			placeOrderFuiouParams.setMerchantSecurit(fuiouConstan.getMerchantSecurit());
			placeOrderFuiouParams.setUrl(fuiouConstan.getSendCodeAgainUrl());
			placeOrderFuiouParams.setUserId(req.getUserId());
			placeOrderFuiouParams.setParams(param);
			placeOrderFuiouParams.setLogParam(logParam);

			return (P) placeOrderFuiouParams;
		} catch (Exception e) {
			logger.error("【pay】【FUIOU】验证码请求参数封装出错！orderId:" + req.getPayOrderId(), e);
			throw new YYPayException(PayRspCodeEnum.COMMON_ERROR_UNKNOWN_EXCEPTION, "验证码请求参数封装失败！");
		}
	}

	/**
	 * 再次协议支付获取验证码响应转换
	 *
	 * @param rsp
	 * @return
	 * @throws Exception
	 * @author heizq
	 * @date 2017-05-12 09:59:02
	 * @since v1.2.0
	 */
	public <C extends Content> SendVerifyCodeYYContent transformProtocolAgainSendVerifyCodeContent(C rsp) throws Exception {
		ProtocolPlaceOrderAgainFuiouContent content = (ProtocolPlaceOrderAgainFuiouContent) rsp;
		try {
			SendVerifyCodeYYContent sendVerifyCodeYYContent = new SendVerifyCodeYYContent();
			if (content == null) {
				sendVerifyCodeYYContent.setResultCode(PayRspCodeEnum.PAY_CODE_PAY_FAIL.getValue());
				return sendVerifyCodeYYContent;
			}
			logger.info("【pay】【FUIOU】发送验证码响应参数:{}", content.toString());

			// 支付id解析
			PayBusiIdVO payOrderIdVo = CommonIdUtils.getPayBusiIdVo(content.getMchntorderid());
			FuiouExtConstant fuiouConstan = fuiouPayInfoService.getMerchantInfo(FuiouExtConstant.class, payOrderIdVo.getMerchantCode(),
					PaymentEnum.FUIOU, PayTypeEnum.PAY, PayModeEnum.AUTH_PAY);

			// 验签
			if (FuiouSignUtil.checkFuiouSign(content, content.getSign(), fuiouConstan.getMerchantSecurit())) {
				if (FuiouRespConstant.RESPONSECODE_SUCCESS.equals(content.getResponsecode())) {
					logger.info("【pay】【FUIOU】订单号：{}，获取支付验证码成功！", content.getMchntorderid());
					sendVerifyCodeYYContent.setResultCode(PayRspCodeEnum.SUCCESS.getValue());
					sendVerifyCodeYYContent.setToken(content.getSignpay());
				} else {
					logger.info("【pay】【FUIOU】订单号：{}，获取支付验证码失败！result:{}", content.getMchntorderid(), content.toString());
					sendVerifyCodeYYContent.setResultCode(PayRspCodeEnum.PAY_CODE_GET_PAY_VERIFY_CODE_FAIL.getValue());
				}

				// 响应信息具体
				sendVerifyCodeYYContent.setResultMsg(content.getResponsemsg());
				sendVerifyCodeYYContent.setPayOrderId(content.getMchntorderid());
			} else {
				sendVerifyCodeYYContent.setResultCode(PayRspCodeEnum.PAY_CODE_CHECK_SIGN_FAIL.getValue());
				sendVerifyCodeYYContent.setResultMsg("获取验证码验签失败");
				logger.error("【pay】【FUIOU】获取验证码验签失败！orderId:{}", content.getMchntorderid());
			}

			sendVerifyCodeYYContent.setSerialNo(content.getOrderid());
			sendVerifyCodeYYContent.setReqUrl(fuiouConstan.getSendCodeAgainUrl());
			sendVerifyCodeYYContent.setRspContent(content.getRspContent());

			return sendVerifyCodeYYContent;
		} catch (Exception e) {
			logger.error("【pay】【FUIOU】验证码响应处理出错！orderId:" + content, e);
			throw new YYPayException(PayRspCodeEnum.COMMON_ERROR_UNKNOWN_EXCEPTION, "验证码响应处理失败！");
		}
	}

	/**
	 * 再次协议支付获取验证码重发参数转换
	 *
	 * @param req
	 * @return
	 * @throws Exception
	 * @author heizq
	 * @date 2017-05-12 09:32:56
	 * @since v1.2.0
	 */
	public <P extends Params> P transformProtocolAgainReSendVerifyCodeParams(SendVerifyCodeYYParams req) throws Exception {
		try {
			logger.debug("【pay】【FUIOU】发送验证码请求参数:{}", JSON.toJSONString(req));

			FuiouExtConstant fuiouConstan = fuiouPayInfoService.getMerchantInfo(FuiouExtConstant.class, req.getMerchantCode(), PaymentEnum.FUIOU,
					PayTypeEnum.PAY, PayModeEnum.AUTH_PAY);

			ProtocolOrderAgainRetryReqData orderReqData = new ProtocolOrderAgainRetryReqData();
			orderReqData.setVersion(fuiouConstan.getProtocolVersion());
			orderReqData.setMchntcd(fuiouConstan.getMerchantId());// 商户代码
			orderReqData.setType(fuiouConstan.getType());// 交易类型
			orderReqData.setUserid(req.getUserId());
			orderReqData.setAmt(req.getAmount() + "");
			orderReqData.setSigntp(fuiouConstan.getSignType());
			orderReqData.setUserip(req.getUserIp());
			orderReqData.setOrderId(req.getSerialNo());
			orderReqData.setProtocolNo(req.getProtocolNo());
			orderReqData.setBackurl(fuiouConstan.getProtocolBackUrl());

			String signPlain = FuiouSignUtil.createFuiouSign(orderReqData, fuiouConstan.getMerchantSecurit());
			logger.debug("【pay】【FUIOU】获取验证码sign:{}", signPlain);

			orderReqData.setSign(signPlain);
			logger.info("【pay】【FUIOU】首次协议支付获取验证码,订单信息:{}", JSON.toJSONString(orderReqData));

			Map<String, String> param = new HashMap<String, String>();
			param.put("MCHNTCD", fuiouConstan.getMerchantId());
			param.put("APIFMS", DESCoderFUIOU.desEncrypt(orderReqData.toXml(), DESCoderFUIOU.getKeyLength8(fuiouConstan.getMerchantSecurit())));

			Map<String, String> logParam = new HashMap<String, String>();
			logParam.put("MCHNTCD", fuiouConstan.getMerchantId());
			logParam.put("APIFMS", orderReqData.toXml());

			ProtocolPlaceOrderAgainRetryFuiouParams placeOrderFuiouParams = new ProtocolPlaceOrderAgainRetryFuiouParams();
			placeOrderFuiouParams.setMerchantSecurit(fuiouConstan.getMerchantSecurit());
			placeOrderFuiouParams.setUrl(fuiouConstan.getSendCodeAgainRetryUrl());
			placeOrderFuiouParams.setUserId(req.getUserId());
			placeOrderFuiouParams.setParams(param);
			placeOrderFuiouParams.setLogParam(logParam);

			return (P) placeOrderFuiouParams;
		} catch (Exception e) {
			logger.error("【pay】【FUIOU】验证码请求参数封装出错！orderId:" + req.getPayOrderId(), e);
			throw new YYPayException(PayRspCodeEnum.COMMON_ERROR_UNKNOWN_EXCEPTION, "验证码请求参数封装失败！");
		}
	}

	/**
	 * 再次协议支付获取验证码响重发应转换
	 *
	 * @param rsp
	 * @return
	 * @throws Exception
	 * @author heizq
	 * @date 2017-05-12 09:59:02
	 * @since v1.2.0
	 */
	public <C extends Content> SendVerifyCodeYYContent transformProtocolAgainReSendVerifyCodeContent(C rsp) throws Exception {
		ProtocolPlaceOrderAgainRetryFuiouContent content = (ProtocolPlaceOrderAgainRetryFuiouContent) rsp;
		try {
			SendVerifyCodeYYContent sendVerifyCodeYYContent = new SendVerifyCodeYYContent();
			if (content == null) {
				sendVerifyCodeYYContent.setResultCode(PayRspCodeEnum.PAY_CODE_PAY_FAIL.getValue());
				return sendVerifyCodeYYContent;
			}
			logger.info("【pay】【FUIOU】发送验证码响应参数:{}", content.toString());

			// 支付id解析
			PayBusiIdVO payOrderIdVo = CommonIdUtils.getPayBusiIdVo(content.getMchntOrderId());
			FuiouExtConstant fuiouConstan = fuiouPayInfoService.getMerchantInfo(FuiouExtConstant.class, payOrderIdVo.getMerchantCode(),
					PaymentEnum.FUIOU, PayTypeEnum.PAY, PayModeEnum.AUTH_PAY);

			// 验签
			if (FuiouSignUtil.checkFuiouSign(content, content.getSign(), fuiouConstan.getMerchantSecurit())) {
				if (FuiouRespConstant.RESPONSECODE_SUCCESS.equals(content.getResponsecode())) {
					logger.info("【pay】【FUIOU】订单号：{}，获取支付验证码成功！", content.getOrderid());
					sendVerifyCodeYYContent.setResultCode(PayRspCodeEnum.SUCCESS.getValue());
					sendVerifyCodeYYContent.setToken(content.getSignpay());
				} else {
					logger.info("【pay】【FUIOU】订单号：{}，获取支付验证码失败！result:{}", content.getOrderid(), content.toString());
					sendVerifyCodeYYContent.setResultCode(PayRspCodeEnum.PAY_CODE_GET_PAY_VERIFY_CODE_FAIL.getValue());
				}

				// 响应信息具体
				sendVerifyCodeYYContent.setResultMsg(content.getResponsemsg());
				sendVerifyCodeYYContent.setSerialNo(content.getOrderid());
			} else {
				sendVerifyCodeYYContent.setResultCode(PayRspCodeEnum.PAY_CODE_CHECK_SIGN_FAIL.getValue());
				sendVerifyCodeYYContent.setResultMsg("获取验证码验签失败");
				logger.error("【pay】【FUIOU】获取验证码验签失败！orderId:{}", content.getOrderid());
			}

			sendVerifyCodeYYContent.setSerialNo(content.getOrderid());
			sendVerifyCodeYYContent.setReqUrl(fuiouConstan.getSendCodeAgainRetryUrl());
			sendVerifyCodeYYContent.setRspContent(content.getRsqContent());

			return sendVerifyCodeYYContent;
		} catch (Exception e) {
			logger.error("【pay】【FUIOU】验证码响应处理出错！orderId:" + content, e);
			throw new YYPayException(PayRspCodeEnum.COMMON_ERROR_UNKNOWN_EXCEPTION, "验证码响应处理失败！");
		}
	}

	/**
	 * 协议支付首次支付请求参数转换
	 *
	 * @param req
	 * @return
	 * @throws Exception
	 * @author heizq
	 * @date 2017-05-12 10:46:40
	 * @since v1.2.0
	 */
	public <P extends Params> P transformProtocolPayOrdeParams(PayOrderYYParams req) throws Exception {
		try {
			logger.debug("【pay】【FUIOU】支付请求参数:{}", JSON.toJSONString(req));

			FuiouExtConstant fuiouConstan = fuiouPayInfoService.getMerchantInfo(FuiouExtConstant.class, req.getMerchantCode(), PaymentEnum.FUIOU,
					PayTypeEnum.PAY, PayModeEnum.AUTH_PAY);

			ProtocolPayReqData payReqData = new ProtocolPayReqData();
			payReqData.setVersion(fuiouConstan.getProtocolVersion());
			payReqData.setUserip(req.getUserIp());
			payReqData.setType(fuiouConstan.getType());
			payReqData.setMchntorderid(req.getPayOrderId());
			payReqData.setUserid(req.getUserId());
			payReqData.setOrderid(req.getSerialNo());
			payReqData.setBankcard(req.getCardNo());
			payReqData.setMobile(req.getPhone());
			payReqData.setVercd(req.getValidCode());
			payReqData.setSigntp(fuiouConstan.getSignType());
			payReqData.setMchntcd(fuiouConstan.getMerchantId());

			String signPlain = FuiouSignUtil.createFuiouSign(payReqData, fuiouConstan.getMerchantSecurit());
			logger.debug("【pay】【FUIOU】富友支付，支付sign:{}", signPlain);

			payReqData.setSign(signPlain);
			payReqData.setSignpay(req.getToken());
			payReqData.setVercd(req.getValidCode());

			Map<String, String> param = new HashMap<String, String>();
			param.put("MCHNTCD", fuiouConstan.getMerchantId());
			param.put("APIFMS", DESCoderFUIOU.desEncrypt(payReqData.toXml(), DESCoderFUIOU.getKeyLength8(fuiouConstan.getMerchantSecurit())));

			Map<String, String> logParam = new HashMap<String, String>();
			logParam.put("MCHNTCD", fuiouConstan.getMerchantId());
			logParam.put("APIFMS", payReqData.toXml());

			ProtocolPayOrderFuiouParams payOrderFuiouParams = new ProtocolPayOrderFuiouParams();
			payOrderFuiouParams.setMerchantSecurit(fuiouConstan.getMerchantSecurit());
			payOrderFuiouParams.setUrl(fuiouConstan.getPayProtocolUrl());
			payOrderFuiouParams.setUserId(req.getUserId());
			payOrderFuiouParams.setParams(param);
			payOrderFuiouParams.setLogParam(logParam);

			return (P) payOrderFuiouParams;
		} catch (Exception e) {
			logger.error("【pay】【FUIOU】支付请求参数封装出错！orderId:" + req.getPayOrderId(), e);
			throw new YYPayException(PayRspCodeEnum.COMMON_ERROR_UNKNOWN_EXCEPTION, "支付请求参数封装失败！");
		}
	}

	public <C extends Content> PayOrderYYContent transformProtocolPayOrdeContent(C rsp) throws Exception {
		ProtocolPayOrderFuiouContent payOrderFuiouContent = (ProtocolPayOrderFuiouContent) rsp;
		try {
			PayOrderYYContent payOrderYYContent = new PayOrderYYContent();
			if (payOrderFuiouContent == null) {
				payOrderYYContent.setResultCode(PayRspCodeEnum.PAY_CODE_PAY_FAIL.getValue());
				return payOrderYYContent;
			}
			logger.info("【pay】【FUIOU】订单号：{}，富友支付响应参数！result:{}", payOrderFuiouContent.getOrderid(), payOrderFuiouContent.toString());
			// 支付id解析
			PayBusiIdVO payOrderIdVo = CommonIdUtils.getPayBusiIdVo(payOrderFuiouContent.getMchntorderid());
			FuiouExtConstant fuiouConstan = fuiouPayInfoService.getMerchantInfo(FuiouExtConstant.class, payOrderIdVo.getMerchantCode(),
					PaymentEnum.FUIOU, PayTypeEnum.PAY, PayModeEnum.AUTH_PAY);

			// 验签
			if (FuiouSignUtil.checkFuiouSign(payOrderFuiouContent, payOrderFuiouContent.getSign(), fuiouConstan.getMerchantSecurit())) {
				// 成功
				if (FuiouRespConstant.RESPONSECODE_SUCCESS.equals(payOrderFuiouContent.getResponsecode())
						|| FuiouRespConstant.RESPONSECODE_QUERY_SUCCESS.equals(payOrderFuiouContent.getResponsecode())) {
					logger.info("【pay】【FUIOU】订单号：{}，支付成功！", payOrderFuiouContent.getMchntorderid());
					payOrderYYContent.setResultCode(PayRspCodeEnum.SUCCESS.getValue());
					payOrderYYContent.setResultMsg(payOrderFuiouContent.getResponsemsg());
					payOrderYYContent.setSerialNo(payOrderFuiouContent.getOrderid());
				}
				// 验证码无效或错误
				else if (FuiouRespConstant.VALIDATE_CODE_ERROR.equals(payOrderFuiouContent.getResponsecode())) {
					logger.info("【pay】【FUIOU】订单号：{}，支付验证码错误或无效！result:{}", payOrderFuiouContent.getOrderid(), payOrderFuiouContent.toString());
					payOrderYYContent.setResultCode(PayRspCodeEnum.USER_VERIFY_CODE_ERROR.getValue());
					payOrderYYContent.setResultMsg("验证码错误或失效");
				}
				// 处理中
				else if (FuiouRespConstant.RESPONSECODE_UNGETBANKRESULT.equals(payOrderFuiouContent.getResponsecode())) {
					logger.info("【pay】【FUIOU】订单号：{}，支付订单挂起！result:{}", payOrderFuiouContent.getOrderid(), payOrderFuiouContent.toString());
					payOrderYYContent.setResultCode(PayRspCodeEnum.PAY_CODE_DEALING.getValue());
					payOrderYYContent.setResultMsg("处理中");
				}
				// 失败
				else {
					logger.info("【pay】【FUIOU】订单号：{}，支付失败！result:{}", payOrderFuiouContent.getOrderid(), payOrderFuiouContent.toString());
					payOrderYYContent.setResultCode(PayRspCodeEnum.PAY_CODE_PAY_FAIL.getValue());
					payOrderYYContent.setResultMsg(payOrderFuiouContent.getResponsemsg());
				}
				payOrderYYContent.setAmount(Integer.valueOf(payOrderFuiouContent.getAmt()));
				payOrderYYContent.setPayOrderId(payOrderFuiouContent.getMchntorderid());
			} else {
				payOrderYYContent.setResultCode(PayRspCodeEnum.PAY_CODE_CHECK_SIGN_FAIL.getValue());
				payOrderYYContent.setResultMsg("支付验签失败");
				logger.error("【pay】【FUIOU】富友支付查询订单验签失败！orderId:{}", payOrderFuiouContent.getMchntorderid());
			}

			payOrderYYContent.setPayOrderId(payOrderFuiouContent.getMchntorderid());
			payOrderYYContent.setUserId(payOrderFuiouContent.getUserId());
			payOrderYYContent.setReqUrl(fuiouConstan.getPayProtocolUrl());
			payOrderYYContent.setRspContent(payOrderFuiouContent.getRsqContent());
			payOrderYYContent.setProtocolNo(payOrderFuiouContent.getProtocolNo());
			return payOrderYYContent;
		} catch (Exception e) {
			logger.error("【pay】【FUIOU】支付响应处理出错！orderId:" + payOrderFuiouContent, e);
			throw new YYPayException(PayRspCodeEnum.COMMON_ERROR_UNKNOWN_EXCEPTION, "支付响应处理失败！");
		}
	}

	/**
	 * 协议支付再次支付请求参数转换
	 *
	 * @param req
	 * @return
	 * @throws Exception
	 * @author heizq
	 * @date 2017-05-12 10:46:40
	 * @since v1.2.0
	 */
	public <P extends Params> P transformProtocolAgainPayOrdeParams(PayOrderYYParams req) throws Exception {
		try {
			logger.debug("【pay】【FUIOU】支付请求参数:{}", JSON.toJSONString(req));

			FuiouExtConstant fuiouConstan = fuiouPayInfoService.getMerchantInfo(FuiouExtConstant.class, req.getMerchantCode(), PaymentEnum.FUIOU,
					PayTypeEnum.PAY, PayModeEnum.AUTH_PAY);

			ReProtocolPayReqData payReqData = new ReProtocolPayReqData();
			payReqData.setVersion(fuiouConstan.getProtocolVersion());
			payReqData.setUserip(req.getUserIp());
			payReqData.setType(fuiouConstan.getType());
			payReqData.setMchntorderid(req.getPayOrderId());
			payReqData.setUserid(req.getUserId());
			payReqData.setOrderid(req.getSerialNo());
			payReqData.setVercd(req.getValidCode());
			payReqData.setSigntp(fuiouConstan.getSignType());
			payReqData.setMchntcd(fuiouConstan.getMerchantId());
			payReqData.setProtocolNo(req.getProtocolNo());

			String signPlain = FuiouSignUtil.createFuiouSign(payReqData, fuiouConstan.getMerchantSecurit());
			logger.debug("【pay】【FUIOU】富友支付，支付sign:{}", signPlain);

			payReqData.setSign(signPlain);
			payReqData.setSignpay(req.getToken());
			payReqData.setVercd(req.getValidCode());

			Map<String, String> param = new HashMap<String, String>();
			param.put("MCHNTCD", fuiouConstan.getMerchantId());
			param.put("APIFMS", DESCoderFUIOU.desEncrypt(payReqData.toXml(), DESCoderFUIOU.getKeyLength8(fuiouConstan.getMerchantSecurit())));

			Map<String, String> logParam = new HashMap<String, String>();
			logParam.put("MCHNTCD", fuiouConstan.getMerchantId());
			logParam.put("APIFMS", payReqData.toXml());

			ProtocolPayOrderAgainFuiouParams payOrderFuiouParams = new ProtocolPayOrderAgainFuiouParams();
			payOrderFuiouParams.setMerchantSecurit(fuiouConstan.getMerchantSecurit());
			payOrderFuiouParams.setUrl(fuiouConstan.getPayAaginUrl());
			payOrderFuiouParams.setUserId(req.getUserId());
			payOrderFuiouParams.setParams(param);
			payOrderFuiouParams.setLogParam(logParam);

			return (P) payOrderFuiouParams;
		} catch (Exception e) {
			logger.error("【pay】【FUIOU】支付请求参数封装出错！orderId:" + req.getPayOrderId(), e);
			throw new YYPayException(PayRspCodeEnum.COMMON_ERROR_UNKNOWN_EXCEPTION, "支付请求参数封装失败！");
		}
	}

	public <C extends Content> PayOrderYYContent transformProtocolAgainPayOrdeContent(C rsp) throws Exception {
		ProtocolPayOrderAgainFuiouContent payOrderFuiouContent = (ProtocolPayOrderAgainFuiouContent) rsp;
		try {
			PayOrderYYContent payOrderYYContent = new PayOrderYYContent();
			if (payOrderFuiouContent == null) {
				payOrderYYContent.setResultCode(PayRspCodeEnum.PAY_CODE_PAY_FAIL.getValue());
				return payOrderYYContent;
			}
			logger.info("【pay】【FUIOU】订单号：{}，富友支付响应参数！result:{}", payOrderFuiouContent.getOrderid(), payOrderFuiouContent.toString());
			// 支付id解析
			PayBusiIdVO payOrderIdVo = CommonIdUtils.getPayBusiIdVo(payOrderFuiouContent.getMchntorderid());
			FuiouExtConstant fuiouConstan = fuiouPayInfoService.getMerchantInfo(FuiouExtConstant.class, payOrderIdVo.getMerchantCode(),
					PaymentEnum.FUIOU, PayTypeEnum.PAY, PayModeEnum.AUTH_PAY);

			// 验签
			if (FuiouSignUtil.checkFuiouSign(payOrderFuiouContent, payOrderFuiouContent.getSign(), fuiouConstan.getMerchantSecurit())) {
				// 成功
				if (FuiouRespConstant.RESPONSECODE_SUCCESS.equals(payOrderFuiouContent.getResponsecode())
						|| FuiouRespConstant.RESPONSECODE_QUERY_SUCCESS.equals(payOrderFuiouContent.getResponsecode())) {
					logger.info("【pay】【FUIOU】订单号：{}，支付成功！", payOrderFuiouContent.getMchntorderid());
					payOrderYYContent.setResultCode(PayRspCodeEnum.SUCCESS.getValue());
					payOrderYYContent.setResultMsg(payOrderFuiouContent.getResponsemsg());
					payOrderYYContent.setSerialNo(payOrderFuiouContent.getOrderid());
				}
				// 验证码无效或错误
				else if (FuiouRespConstant.VALIDATE_CODE_ERROR.equals(payOrderFuiouContent.getResponsecode())) {
					logger.info("【pay】【FUIOU】订单号：{}，支付验证码错误或无效！result:{}", payOrderFuiouContent.getOrderid(), payOrderFuiouContent.toString());
					payOrderYYContent.setResultCode(PayRspCodeEnum.USER_VERIFY_CODE_ERROR.getValue());
					payOrderYYContent.setResultMsg("验证码错误或失效");
				}
				// 处理中
				else if (FuiouRespConstant.RESPONSECODE_UNGETBANKRESULT.equals(payOrderFuiouContent.getResponsecode())) {
					logger.info("【pay】【FUIOU】订单号：{}，支付订单挂起！result:{}", payOrderFuiouContent.getOrderid(), payOrderFuiouContent.toString());
					payOrderYYContent.setResultCode(PayRspCodeEnum.PAY_CODE_DEALING.getValue());
					payOrderYYContent.setResultMsg("处理中");
				}
				// 失败
				else {
					logger.info("【pay】【FUIOU】订单号：{}，支付失败！result:{}", payOrderFuiouContent.getOrderid(), payOrderFuiouContent.toString());
					payOrderYYContent.setResultCode(PayRspCodeEnum.PAY_CODE_PAY_FAIL.getValue());
					payOrderYYContent.setResultMsg(payOrderFuiouContent.getResponsemsg());
				}
				payOrderYYContent.setAmount(Integer.valueOf(payOrderFuiouContent.getAmt()));
				payOrderYYContent.setPayOrderId(payOrderFuiouContent.getMchntorderid());
			} else {
				payOrderYYContent.setResultCode(PayRspCodeEnum.PAY_CODE_CHECK_SIGN_FAIL.getValue());
				payOrderYYContent.setResultMsg("支付验签失败");
				logger.error("【pay】【FUIOU】富友支付查询订单验签失败！orderId:{}", payOrderFuiouContent.getMchntorderid());
			}

			payOrderYYContent.setPayOrderId(payOrderFuiouContent.getMchntorderid());
			payOrderYYContent.setUserId(payOrderFuiouContent.getUserId());
			payOrderYYContent.setReqUrl(fuiouConstan.getPayAaginUrl());
			payOrderYYContent.setRspContent(payOrderFuiouContent.getRsqContent());
			return payOrderYYContent;
		} catch (Exception e) {
			logger.error("【pay】【FUIOU】支付响应处理出错！orderId:" + payOrderFuiouContent, e);
			throw new YYPayException(PayRspCodeEnum.COMMON_ERROR_UNKNOWN_EXCEPTION, "支付响应处理失败！");
		}
	}
}
